home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / storage / ipc / ipc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-05  |  26.2 KB  |  1,059 lines

  1. /* ----------------------------------------------------------------
  2.  * ipc.c --
  3.  *      POSTGRES inter-process communication definitions.
  4.  *
  5.  * Identification:
  6.  *      $Header: /private/postgres/src/storage/ipc/RCS/ipc.c,v 1.37 1991/10/16 16:56:46 hong Exp $
  7.  * ----------------------------------------------------------------
  8.  */
  9.  
  10.  
  11. #include <sys/types.h>
  12. #include <sys/file.h>
  13. #include <stdio.h>
  14. #include <errno.h>
  15.  
  16. /* XXX - the following  dependency should be moved into the defaults.mk file */
  17. #ifndef    _IPC_
  18. #define _IPC_
  19. #ifndef sequent 
  20.  
  21. #include <sys/ipc.h>
  22. #include <sys/sem.h>
  23. #include <sys/shm.h>
  24.  
  25. #else
  26.  
  27. #include "/usr/att/usr/include/sys/ipc.h"
  28. #include "/usr/att/usr/include/sys/sem.h"
  29. #include "/usr/att/usr/include/sys/shm.h"
  30.  
  31. #endif /* defined(sequent) */
  32. #endif
  33.  
  34. #include "storage/ipci.h"        /* for PrivateIPCKey XXX */
  35. #include "storage/ipc.h"
  36. #include "tmp/align.h"
  37. #include "utils/log.h"
  38. #include "tcop/slaves.h"
  39.  
  40. int UsePrivateMemory = 0;
  41.  
  42. #ifdef PARALLELDEBUG
  43. #include "executor/paralleldebug.h"
  44. #endif
  45.  
  46. /* ----------------------------------------------------------------
  47.  *            exit() handling stuff
  48.  * ----------------------------------------------------------------
  49.  */
  50.  
  51. #define MAX_ON_EXITS 20
  52.  
  53. static struct ONEXIT {
  54.     void (*function)();
  55.     caddr_t arg;
  56. } onexit_list[ MAX_ON_EXITS ];
  57.  
  58. static int onexit_index;
  59.  
  60. typedef struct _PrivateMemStruct {
  61.     int id;
  62.     char *memptr;
  63. } PrivateMem;
  64.  
  65. PrivateMem IpcPrivateMem[16];
  66.  
  67. int
  68. PrivateMemoryCreate ( memKey , size , permission )
  69.      IpcMemoryKey memKey;
  70.      uint32 size;
  71. {
  72.     static int memid = 0;
  73.     
  74.     UsePrivateMemory = 1;
  75.  
  76.     IpcPrivateMem[memid].id = memid;
  77.     IpcPrivateMem[memid].memptr = malloc(size);
  78.     if (IpcPrivateMem[memid].memptr == NULL)
  79.        elog(WARN, "PrivateMemoryCreate: not enough memory to malloc");
  80.     
  81.     return (memid++);
  82. }
  83.  
  84. char *
  85. PrivateMemoryAttach ( memid , ignored1 , ignored2 )
  86.      IpcMemoryId memid;
  87.      int ignored1;
  88.      int ignored2;
  89. {
  90.     return ( IpcPrivateMem[memid].memptr );
  91. }
  92.  
  93.  
  94. /* ----------------------------------------------------------------
  95.  *    exitpg
  96.  *
  97.  *    this function calls all the callbacks registered
  98.  *    for it (to free resources) and then calls exit.
  99.  *    This should be the only function to call exit().
  100.  *    -cim 2/6/90
  101.  * ----------------------------------------------------------------
  102.  */
  103. int exitpg_inprogress = 0;
  104.  
  105. void
  106. exitpg(code)
  107.     int code;
  108. {
  109.     int i;
  110.  
  111.     /* ----------------
  112.      *    if exitpg_inprocess is true, then it means that we
  113.      *  are being invoked from within an on_exit() handler
  114.      *  and so we return immediately to avoid recursion.
  115.      * ----------------
  116.      */
  117.     if (exitpg_inprogress)
  118.     return;
  119.  
  120.     exitpg_inprogress = 1;
  121.  
  122.     /* ----------------
  123.      *    call all the callbacks registered before calling exit().
  124.      * ----------------
  125.      */
  126.     for (i = onexit_index - 1; i >= 0; --i)
  127.     (*onexit_list[i].function)(code, onexit_list[i].arg);
  128.  
  129.     exit(code);
  130. }
  131.  
  132. /* ------------------
  133.  * Run all of the on_exitpg routines but don't exit in the end.
  134.  * This is used by the postmaster to re-initialize shared memory and
  135.  * semaphores after a backend dies horribly
  136.  * ------------------
  137.  */
  138. void
  139. quasi_exitpg()
  140. {
  141.     int i;
  142.  
  143.     /* ----------------
  144.      *    if exitpg_inprocess is true, then it means that we
  145.      *  are being invoked from within an on_exit() handler
  146.      *  and so we return immediately to avoid recursion.
  147.      * ----------------
  148.      */
  149.     if (exitpg_inprogress)
  150.     return;
  151.  
  152.     exitpg_inprogress = 1;
  153.  
  154.     /* ----------------
  155.      *    call all the callbacks registered before calling exit().
  156.      * ----------------
  157.      */
  158.     for (i = onexit_index - 1; i >= 0; --i)
  159.     (*onexit_list[i].function)(0, onexit_list[i].arg);
  160.  
  161.     onexit_index = 0;
  162.     exitpg_inprogress = 0;
  163. }
  164.  
  165. /* ----------------------------------------------------------------
  166.  *    on_exitpg
  167.  *
  168.  *    this function adds a callback function to the list of
  169.  *    functions invoked by exitpg().    -cim 2/6/90
  170.  * ----------------------------------------------------------------
  171.  */
  172.  
  173. on_exitpg(function, arg)
  174.     void (*function)();
  175.     caddr_t arg;
  176. {
  177.     if (onexit_index >= MAX_ON_EXITS)
  178.     return(-1);
  179.     
  180.     onexit_list[ onexit_index ].function = function;
  181.     onexit_list[ onexit_index ].arg = arg;
  182.  
  183.     ++onexit_index;
  184.     
  185.     return(0);
  186. }
  187.  
  188. /****************************************************************************/
  189. /*   IPCPrivateSemaphoreKill(status, semId)                    */
  190. /*                                        */
  191. /****************************************************************************/
  192. void
  193. IPCPrivateSemaphoreKill(status, semId)
  194.     int    status;
  195.     int    semId;        /* caddr_t */
  196. {
  197.     union semun    semun;
  198.     semctl(semId, 0, IPC_RMID, semun);
  199. }
  200.  
  201.  
  202. /****************************************************************************/
  203. /*   IPCPrivateMemoryKill(status, shmId)                    */
  204. /*                                        */
  205. /****************************************************************************/
  206. void
  207. IPCPrivateMemoryKill(status, shmId)
  208.     int    status;
  209.     int    shmId;        /* caddr_t */
  210. {
  211.     if ( UsePrivateMemory ) {
  212.     /* free ( IpcPrivateMem[shmId].memptr ); */
  213.     } else {
  214.     shmctl(shmId, IPC_RMID, (struct shmid_ds *)NULL);
  215.     } 
  216. }
  217.  
  218.  
  219. /****************************************************************************/
  220. /*   IpcSemaphoreCreate(semKey, semNum, permission, semStartValue)          */
  221. /*                                            */
  222. /*    - returns a semaphore identifier:                        */
  223. /*                                            */
  224. /* if key doesn't exist: return a new id,      status:= IpcSemIdNotExist    */
  225. /* if key exists:        return the old id,    status:= IpcSemIdExist        */
  226. /* if semNum > MAX :     return # of argument, status:=IpcInvalidArgument   */
  227. /*                                        */
  228. /****************************************************************************/
  229.  
  230. /*
  231.  * Note:
  232.  * XXX    This should be split into two different calls.  One should
  233.  * XXX    be used to create a semaphore set.  The other to "attach" a
  234.  * XXX    existing set.  It should be an error for the semaphore set
  235.  * XXX    to to already exist or for it not to, respectively.
  236.  *
  237.  *    Currently, the semaphore sets are "attached" and an error
  238.  *    is detected only when a later shared memory attach fails.
  239.  */
  240.     
  241. IpcSemaphoreId
  242. IpcSemaphoreCreate(semKey, semNum, permission, semStartValue, status)
  243.     IpcSemaphoreKey semKey;           /* input patameter  */
  244.     int            semNum;        /* input patameter  */
  245.     int            permission;        /* input patameter  */
  246.     int            semStartValue;    /* input patameter  */
  247.     int            *status;        /* output parameter */
  248. {
  249.     int        i;
  250.     int        errStatus;
  251.     int        semId;
  252.     ushort    array[IPC_NMAXSEM];
  253.     union semun    semun;
  254.     
  255.     /* get a semaphore if non-existent */
  256.     /* check arguments    */
  257.     if (semNum > IPC_NMAXSEM || semNum <= 0)  {
  258.     *status = IpcInvalidArgument;
  259.     return(2);    /* returns the number of the invalid argument    */
  260.     }
  261.     
  262. #ifdef linux
  263.     semId = semget(semKey, 0, permission);
  264. #else
  265.     semId = semget(semKey, 0, 0);
  266. #endif
  267.     if (semId == -1) {
  268.     *status = IpcSemIdNotExist;    /* there doesn't exist a semaphore */
  269. #ifdef DEBUG_IPC
  270.     fprintf(stderr,"calling semget with %d, %d , %d\n",
  271.         semKey,
  272.         semNum,
  273.         IPC_CREAT|permission );
  274. #endif
  275.     semId = semget(semKey, semNum, IPC_CREAT|permission);
  276.  
  277.     if (semId < 0) {
  278.         perror("semget");
  279.         exitpg(3);
  280.     }
  281.     for (i = 0; i < semNum; i++) {
  282.         array[i] = semStartValue;
  283.     }
  284.     semun.array = array;
  285.     errStatus = semctl(semId, 0, SETALL, semun);
  286.     if (errStatus == -1) {
  287.         perror("semctl");
  288.     }
  289.     
  290.     /* if (semKey == PrivateIPCKey) */
  291.     on_exitpg(IPCPrivateSemaphoreKill, (caddr_t)semId);
  292.     
  293.     } else {
  294.     /* there is a semaphore id for this key */
  295.     *status = IpcSemIdExist;
  296.     }
  297.  
  298. #ifdef DEBUG_IPC
  299.     fprintf(stderr,"\nIpcSemaphoreCreate, status %d, returns %d\n",
  300.         *status,
  301.         semId );
  302.     fflush(stdout);
  303.     fflush(stderr);
  304. #endif
  305.     return(semId);
  306. }
  307.  
  308. /* ----------------
  309.  *    IpcSemaphoreCreateWithoutOnExit
  310.  *
  311.  *    this is a copy of IpcSemaphoreCreate, but it doesn't register
  312.  *    an on_exitpg procedure.  This is necessary for the executor
  313.  *    semaphores because we need a special on-exit procedure to
  314.  *    do the right thing depending on if the postgres process is
  315.  *    a master or a slave process.  In a master process, we should
  316.  *    kill the semaphores when we exit but in a slave process we
  317.  *    should release them.
  318.  * ----------------
  319.  */
  320. IpcSemaphoreId
  321. IpcSemaphoreCreateWithoutOnExit(semKey,
  322.                 semNum,
  323.                 permission,
  324.                 semStartValue,
  325.                 status)
  326.     IpcSemaphoreKey semKey;           /* input patameter  */
  327.     int            semNum;        /* input patameter  */
  328.     int            permission;        /* input patameter  */
  329.     int            semStartValue;    /* input patameter  */
  330.     int            *status;        /* output parameter */
  331. {
  332.     int        i;
  333.     int        errStatus;
  334.     int        semId;
  335.     ushort    array[IPC_NMAXSEM];
  336.     union semun    semun;
  337.     
  338.     /* get a semaphore if non-existent */
  339.     /* check arguments    */
  340.     if (semNum > IPC_NMAXSEM || semNum <= 0)  {
  341.     *status = IpcInvalidArgument;
  342.     return(2);    /* returns the number of the invalid argument    */
  343.     }
  344.     
  345. #ifdef linux
  346.     semId = semget(semKey, 0, permission);
  347. #else
  348.     semId = semget(semKey, 0, 0);
  349. #endif
  350.     if (semId == -1) {
  351.     *status = IpcSemIdNotExist;    /* there doesn't exist a semaphore */
  352.     semId = semget(semKey, semNum, IPC_CREAT|permission);
  353.     if (semId < 0) {
  354.         perror("semget");
  355.         exitpg(3);
  356.     }
  357.     for (i = 0; i < semNum; i++) {
  358.         array[i] = semStartValue;
  359.     }
  360.     semun.array = array;
  361.     errStatus = semctl(semId, 0, SETALL, semun);
  362.     if (errStatus == -1) {
  363.         perror("semctl");
  364.     }
  365.     } else {
  366.     /* there is a semaphore id for this key */
  367.     *status = IpcSemIdExist;
  368.     }
  369.     
  370.     return(semId);
  371. }
  372.  
  373.  
  374. /****************************************************************************/
  375. /*   IpcSemaphoreSet()        - sets the initial value of the semaphore   */
  376. /*                                        */
  377. /*    note: the xxx_return variables are only used for debugging.        */
  378. /****************************************************************************/
  379. int IpcSemaphoreSet_return;
  380.  
  381. void
  382. IpcSemaphoreSet(semId, semno, value)
  383.     int        semId;
  384.     int        semno;
  385.     int        value;
  386. {
  387.     int        errStatus;
  388.     union semun    semun;
  389.  
  390.     semun.val = value;
  391.     errStatus = semctl(semId, semno, SETVAL, semun);
  392.     IpcSemaphoreSet_return = errStatus;
  393.     
  394.     if (errStatus == -1)
  395.     perror("semctl");
  396. }
  397.  
  398. /****************************************************************************/
  399. /*   IpcSemaphoreKill(key)    - removes a semaphore                */
  400. /*                                        */
  401. /****************************************************************************/
  402. void
  403. IpcSemaphoreKill(key)
  404.     IpcSemaphoreKey key;
  405. {
  406.     int        i;
  407.     int     semId;
  408.     int        status;
  409.     union semun    semun;
  410.     
  411.     /* kill semaphore if existent */
  412.     
  413. #ifdef linux
  414.     semId = semget(key, 0, 0600);
  415. #else
  416.     semId = semget(key, 0, 0);
  417. #endif
  418.     if (semId != -1)
  419.     semctl(semId, 0, IPC_RMID, semun);
  420. }
  421.  
  422. /****************************************************************************/
  423. /*   IpcSemaphoreLock(semId, sem, lock)    - locks a semaphore            */
  424. /*                                        */
  425. /*    note: the xxx_return variables are only used for debugging.        */
  426. /****************************************************************************/
  427. int IpcSemaphoreLock_return;
  428.  
  429. void
  430. IpcSemaphoreLock(semId, sem, lock)
  431.     IpcSemaphoreId    semId;
  432.     int            sem;
  433.     int            lock;
  434. {
  435.     extern int        errno;
  436.     int            errStatus;
  437.     struct sembuf    sops;
  438.     
  439.     sops.sem_op = lock;
  440.     sops.sem_flg = 0;
  441.     sops.sem_num = sem;
  442.     
  443.     /* ----------------
  444.      *    Note: if errStatus is -1 and errno == EINTR then it means we
  445.      *        returned from the operation prematurely because we were
  446.      *          sent a signal.  So we try and lock the semaphore again.
  447.      *          I am not certain this is correct, but the semantics aren't
  448.      *          clear it fixes problems with parallel abort synchronization,
  449.      *          namely that after processing an abort signal, the semaphore
  450.      *          call returns with -1 (and errno == EINTR) before it should.
  451.      *          -cim 3/28/90
  452.      * ----------------
  453.      */
  454.     do {
  455. #ifndef SINGLE_USER
  456.     /* kai: why was this cast to (struct sembuf **) there ??? */
  457.     errStatus = semop(semId, /* (struct sembuf **) */ &sops, 1);
  458. #else
  459.     errStatus = 0;
  460. #endif
  461.     } while (errStatus == -1 && errno == EINTR);
  462.     
  463.     IpcSemaphoreLock_return = errStatus;
  464.     
  465.     if (errStatus == -1) {
  466.     if (!ParallelExecutorEnabled() && errno == EIDRM)
  467.         /*
  468.          * this is a hack. currently the master backend kills the
  469.          * slave backend by removing the semaphores that they are waiting
  470.          * on.  does not want it to complain.
  471.          */
  472.         perror("semop");
  473.     exitpg(255);
  474.     }
  475. }
  476.  
  477. /* ----------------
  478.  *    IpcSemaphoreSilentLock
  479.  *
  480.  *    This does what IpcSemaphoreLock() does but does not
  481.  *    produce error messages.  
  482.  *
  483.  *    note: the xxx_return variables are only used for debugging.
  484.  * ----------------
  485.  */
  486. int IpcSemaphoreSilentLock_return;
  487.  
  488. void
  489. IpcSemaphoreSilentLock(semId, sem, lock)
  490.     IpcSemaphoreId    semId;
  491.     int            sem;
  492.     int            lock;
  493. {
  494.     int            errStatus;
  495.     struct sembuf    sops;
  496.     
  497.     sops.sem_op = lock;
  498.     sops.sem_flg = 0;
  499.     sops.sem_num = sem;
  500.     
  501.     IpcSemaphoreSilentLock_return =
  502. #ifndef SINGLE_USER
  503.     semop(semId, /* (struct sembuf **) */ &sops, 1);
  504. #else
  505.     0;
  506. #endif
  507. }
  508.  
  509. /****************************************************************************/
  510. /*   IpcSemaphoreUnlock(semId, sem, lock)    - unlocks a semaphore        */
  511. /*                                        */
  512. /*    note: the xxx_return variables are only used for debugging.        */
  513. /****************************************************************************/
  514. int IpcSemaphoreUnlock_return;
  515.     
  516. void
  517. IpcSemaphoreUnlock(semId, sem, lock)
  518.     IpcSemaphoreId    semId;
  519.     int            sem;
  520.     int            lock;
  521. {
  522.     extern int        errno;
  523.     int            errStatus;
  524.     struct sembuf    sops;
  525.     
  526.     sops.sem_op = -lock;
  527.     sops.sem_flg = 0;
  528.     sops.sem_num = sem;
  529.  
  530.     
  531.     /* ----------------
  532.      *    Note: if errStatus is -1 and errno == EINTR then it means we
  533.      *        returned from the operation prematurely because we were
  534.      *          sent a signal.  So we try and lock the semaphore again.
  535.      *          I am not certain this is correct, but the semantics aren't
  536.      *          clear it fixes problems with parallel abort synchronization,
  537.      *          namely that after processing an abort signal, the semaphore
  538.      *          call returns with -1 (and errno == EINTR) before it should.
  539.      *          -cim 3/28/90
  540.      * ----------------
  541.      */
  542.     do {
  543. #ifndef SINGLE_USER
  544.     errStatus = semop(semId, /* (struct sembuf **) */ &sops, 1);
  545. #else
  546.     errStatus = 0;
  547. #endif
  548.     } while (errStatus == -1 && errno == EINTR);
  549.     
  550.     IpcSemaphoreUnlock_return = errStatus;
  551.     
  552.     if (errStatus == -1) {
  553.     perror("semop");
  554.     exitpg(255);
  555.     }
  556. }
  557.  
  558. /* ----------------
  559.  *    IpcSemaphoreSilentUnlock
  560.  *
  561.  *    This does what IpcSemaphoreUnlock() does but does not
  562.  *    produce error messages.  This is used in the slave backends
  563.  *    when they exit because it is possible that the master backend
  564.  *    may have died and removed the semaphore before this code gets
  565.  *    to execute in the slaves.
  566.  *
  567.  *    note: the xxx_return variables are only used for debugging.
  568.  * ----------------
  569.  */
  570. int IpcSemaphoreSilentUnlock_return;
  571.  
  572. void
  573. IpcSemaphoreSilentUnlock(semId, sem, lock)
  574.     IpcSemaphoreId    semId;
  575.     int            sem;
  576.     int            lock;
  577. {
  578.     int            errStatus;
  579.     struct sembuf    sops;
  580.     
  581.     sops.sem_op = -lock;
  582.     sops.sem_flg = 0;
  583.     sops.sem_num = sem;
  584.     
  585.     IpcSemaphoreSilentUnlock_return =
  586. #ifndef SINGLE_USER
  587.     semop(semId, /* (struct sembuf **) */ &sops, 1);
  588. #else
  589.     0;
  590. #endif
  591. }
  592.  
  593. int
  594. IpcSemaphoreGetCount(semId, sem)
  595. IpcSemaphoreId    semId;
  596. int        sem;
  597. {
  598.     int semncnt;
  599.     /* kai: */
  600.     union semun semun;
  601.  
  602.     semncnt = semctl(semId, sem, GETNCNT, semun);
  603.     return semncnt;
  604. }
  605.  
  606. int
  607. IpcSemaphoreGetValue(semId, sem)
  608. IpcSemaphoreId    semId;
  609. int        sem;
  610. {
  611.     int semval;
  612.     /* kai: */
  613.     union semun semun;
  614.  
  615.     semval = semctl(semId, sem, GETVAL, semun);
  616.     return semval;
  617. }
  618.  
  619. /****************************************************************************/
  620. /*   IpcMemoryCreate(memKey)                            */
  621. /*                                        */
  622. /*    - returns the memory identifier, if creation succeeds            */
  623. /*    returns IpcMemCreationFailed, if failure                */
  624. /****************************************************************************/
  625.  
  626. IpcMemoryId
  627. IpcMemoryCreate(memKey, size, permission)
  628.     IpcMemoryKey memKey;
  629.     uint32     size;
  630.     int         permission;
  631. {
  632.     IpcMemoryId     shmid;
  633.     int         errStatus; 
  634.  
  635.     if ( memKey == PrivateIPCKey && !(ParallelExecutorEnabled()) ) {
  636.     /* private */
  637.     shmid = PrivateMemoryCreate ( memKey, size , IPC_CREAT|permission);
  638.     } else {
  639.     shmid = shmget(memKey, size, IPC_CREAT|permission); 
  640.     }
  641.  
  642.     if (shmid < 0) {
  643.     fprintf(stderr,"IpcMemoryCreate: memKey=%d , size=%d , permission=%d", 
  644.          memKey, size , permission );
  645.     perror("IpcMemoryCreate: shmget(..., create, ...) failed");
  646.     return(IpcMemCreationFailed);
  647.     }
  648.     
  649.     /* if (memKey == PrivateIPCKey) */
  650.     on_exitpg(IPCPrivateMemoryKill, (caddr_t)shmid);
  651.     
  652.     return(shmid);
  653. }
  654.  
  655. /* ----------------
  656.  *    IpcMemoryCreateWithoutOnExit
  657.  *
  658.  *    Like IpcSemaphoreCreateWithoutOnExit(), this function
  659.  *    creates shared memory without registering an on_exit
  660.  *    procedure.
  661.  * ----------------
  662.  */
  663. IpcMemoryId
  664. IpcMemoryCreateWithoutOnExit(memKey, size, permission)
  665.     IpcMemoryKey memKey;
  666.     uint32     size;
  667.     int         permission;
  668. {
  669.     IpcMemoryId     shmid;
  670.     int         errStatus; 
  671.     
  672.     if ( memKey == PrivateIPCKey && (!(ParallelExecutorEnabled())) ) {
  673.     /* private */
  674.     shmid = PrivateMemoryCreate ( memKey, size , IPC_CREAT|permission);
  675.     } else {
  676.     shmid = shmget(memKey, size, IPC_CREAT|permission); 
  677.     }
  678.  
  679.     if (shmid < 0) {
  680.     fprintf(stderr,"IpcMemoryCreate: memKey=%d , size=%d , permission=%d", 
  681.          memKey, size , permission );
  682.     perror("IpcMemoryCreateWithoutOnExit: shmget(, IPC_CREAT,) failed");
  683.     return(IpcMemCreationFailed);
  684.     }
  685.  
  686.     return(shmid);
  687. }
  688.  
  689.  
  690. /****************************************************************************/
  691. /*  IpcMemoryIdGet(memKey, size)    returns the shared memory Id         */
  692. /*                    or IpcMemIdGetFailed                */
  693. /****************************************************************************/
  694. IpcMemoryId
  695. IpcMemoryIdGet(memKey, size)
  696.     IpcMemoryKey    memKey;
  697.     uint32        size;
  698. {
  699.     IpcMemoryId    shmid;
  700.     
  701.     /*
  702.      * Linux ipcdelta does not like shmget with flags zero
  703.      */
  704. #ifdef linux
  705.     shmid = shmget(memKey, size, 0600);
  706. #else
  707.     shmid = shmget(memKey, size, 0);
  708. #endif
  709.  
  710.     if (shmid < 0) {
  711.     fprintf(stderr,"IpcMemoryIdGet: memKey=%d , size=%d , permission=%d", 
  712.          memKey, size , 0 );
  713.     perror("IpcMemoryIdGet:  shmget() failed");
  714.     return(IpcMemIdGetFailed);
  715.     }
  716.     
  717.     return(shmid);
  718. }
  719.  
  720.  
  721. /****************************************************************************/
  722. /*  IpcMemoryAttach(memId)    returns the adress of shared memory        */
  723. /*                  or IpcMemAttachFailed                */
  724. /*                                                */
  725. /* CALL IT:  addr = (struct <MemoryStructure> *) IpcMemoryAttach(memId);    */
  726. /*                                        */
  727. /****************************************************************************/
  728. char *
  729. IpcMemoryAttach(memId)
  730.     IpcMemoryId    memId;
  731. {
  732.     char    *memAddress;
  733.     int        errStatus;
  734.     
  735.     if ( UsePrivateMemory ) {
  736.     memAddress = (char *)PrivateMemoryAttach ( memId , 0 , 0 );
  737.     } else {
  738.     /*
  739.      * Under Linux, malloc() handles shared memory segments like any
  740.      * other memory, so it will eventually overwrite the segment, if
  741.      * we don't move it out of the way. So, attach the first segment
  742.      * at address 4 Megabyte, and add 1 Megabyte for each
  743.      * subsequent attach. Hope, that malloc() will change in the
  744.      * future (kai).
  745.      *
  746.      * This was a problem with ipcbeta, as it allocated shared memory
  747.      * low by default. Ipcdelta allocates memory at very high addresses
  748.      * (1 Gigabyte, or so), so disable the work-around again (but leave
  749.      * it here just in case).
  750.      */
  751. /* #ifdef linux */
  752. #if 0
  753. static void *next_address = (void *) 0x400000;
  754.     memAddress = (char *) shmat(memId, next_address, SHM_RND);
  755.     next_address += 0x100000;
  756. #else
  757.     memAddress = (char *) shmat(memId, 0, 0);
  758. #endif
  759.     }
  760.  
  761.     /*    if ( *memAddress == -1) { XXX ??? */
  762.     if ( memAddress == (char *)-1) {
  763.     perror("IpcMemoryAttach: shmat() failed");
  764.     return(IpcMemAttachFailed);
  765.     }
  766.     
  767.     return((char *) memAddress);
  768. }
  769.  
  770.  
  771. /****************************************************************************/
  772. /*  IpcMemoryKill(memKey)            removes a shared memory segment     */
  773. /*                                        */
  774. /****************************************************************************/
  775. void
  776. IpcMemoryKill(memKey)
  777.     IpcMemoryKey    memKey;
  778. {    
  779.     IpcMemoryId        shmid;
  780.     
  781. #ifdef linux
  782.     if (!UsePrivateMemory && (shmid = shmget(memKey, 0, 0600)) >= 0) {
  783. #else
  784.     if (!UsePrivateMemory && (shmid = shmget(memKey, 0, 0)) >= 0) {
  785. #endif
  786.     shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0);
  787.     }
  788.  
  789. #ifdef HAS_TEST_AND_SET
  790. /* ------------------
  791.  *  use hardware locks to replace semaphores for sequent machines
  792.  *  to avoid costs of swapping processes and to provide unlimited
  793.  *  supply of locks.
  794.  * ------------------
  795.  */
  796. static SLock *SLockArray = NULL;
  797. static SLock **FreeSLockPP;
  798. static int *UnusedSLockIP;
  799. static slock_t *SLockMemoryLock;
  800. static IpcMemoryId SLockMemoryId = -1;
  801. static int SLockMemorySize = sizeof(SLock*) + sizeof(int) + 
  802.                  sizeof(slock_t) + NSLOCKS*sizeof(SLock);
  803. void
  804. CreateAndInitSLockMemory(key)
  805. IPCKey key;
  806. {
  807.     int id;
  808.     SLock *slckP;
  809.  
  810.     SLockMemoryId = IpcMemoryCreate(key,
  811.                     SLockMemorySize,
  812.                     0700);
  813.     AttachSLockMemory(key);
  814.     *FreeSLockPP = NULL;
  815.     *UnusedSLockIP = (int)FIRSTFREELOCKID;
  816.     for (id=0; id<(int)FIRSTFREELOCKID; id++) {
  817.     slckP = &(SLockArray[id]);
  818.     S_INIT_LOCK(&(slckP->locklock));
  819.     slckP->flag = NOLOCK;
  820.     slckP->nshlocks = 0;
  821.     S_INIT_LOCK(&(slckP->shlock));
  822.     S_INIT_LOCK(&(slckP->exlock));
  823.     S_INIT_LOCK(&(slckP->comlock));
  824.     slckP->next = NULL;
  825.       }
  826.     return;
  827. }
  828.  
  829. void
  830. AttachSLockMemory(key)
  831. IPCKey key;
  832. {
  833.     char *slockM;
  834.     if (SLockMemoryId == -1)
  835.        SLockMemoryId = IpcMemoryIdGet(key,SLockMemorySize);
  836.     if (SLockMemoryId == -1)
  837.        elog(FATAL, "SLockMemory not in shared memory");
  838.     slockM = IpcMemoryAttach(SLockMemoryId);
  839.     if (slockM == IpcMemAttachFailed)
  840.     elog(FATAL, "AttachSLockMemory: could not attach segment");
  841.     FreeSLockPP = (SLock**)slockM;
  842.     UnusedSLockIP = (int*)(FreeSLockPP + 1);
  843.     SLockMemoryLock = (slock_t*)(UnusedSLockIP + 1);
  844.     S_INIT_LOCK(SLockMemoryLock);
  845.     SLockArray = (SLock*)LONGALIGN((SLockMemoryLock + 1));
  846.     return;
  847. }
  848.  
  849. int
  850. CreateLock()
  851. {
  852.     int lockid;
  853.     SLock *slckP;
  854.  
  855.     S_LOCK(SLockMemoryLock);
  856.     if (*FreeSLockPP != NULL) {
  857.        lockid = *FreeSLockPP - SLockArray;
  858.        *FreeSLockPP = (*FreeSLockPP)->next;
  859.       }
  860.     else {
  861.        lockid = *UnusedSLockIP;
  862.        (*UnusedSLockIP)++;
  863.      }
  864.     slckP = &(SLockArray[lockid]);
  865.     S_INIT_LOCK(&(slckP->locklock));
  866.     slckP->flag = NOLOCK;
  867.     slckP->nshlocks = 0;
  868.     S_INIT_LOCK(&(slckP->shlock));
  869.     S_INIT_LOCK(&(slckP->exlock));
  870.     S_INIT_LOCK(&(slckP->comlock));
  871.     slckP->next = NULL;
  872.     S_UNLOCK(SLockMemoryLock);
  873.     return lockid;
  874. }
  875.  
  876. void
  877. RelinquishLock(lockid)
  878. int lockid;
  879. {
  880.     SLock *slckP;
  881.     slckP = &(SLockArray[lockid]);
  882.     S_LOCK(SLockMemoryLock);
  883.     slckP->next = *FreeSLockPP;
  884.     *FreeSLockPP = slckP;
  885.     S_UNLOCK(SLockMemoryLock);
  886.     return;
  887. }
  888.  
  889. #ifdef LOCKDEBUG
  890. extern int MyPid;
  891. #define PRINT_LOCK(LOCK) printf("(locklock = %d, flag = %d, nshlocks = %d, \
  892. shlock = %d, exlock =%d)\n", LOCK->locklock, \
  893. LOCK->flag, LOCK->nshlocks, LOCK->shlock, \
  894. LOCK->exlock)
  895. #endif
  896.  
  897. void
  898. SharedLock(lockid)
  899. int lockid;
  900. {
  901.     SLock *slckP;
  902. #ifdef PARALLELDEBUG
  903.     BeginParallelDebugInfo(PDI_SHAREDLOCK);
  904. #endif
  905.     slckP = &(SLockArray[lockid]);
  906. #ifdef LOCKDEBUG
  907.     printf("Proc %d SharedLock(%d)\n", MyPid, lockid);
  908.     printf("IN: ");
  909.     PRINT_LOCK(slckP);
  910. #endif
  911. sh_try_again:
  912.     S_LOCK(&(slckP->locklock));
  913.     switch (slckP->flag) {
  914.     case NOLOCK:
  915.        slckP->flag = SHAREDLOCK;
  916.        slckP->nshlocks = 1;
  917.        S_LOCK(&(slckP->exlock));
  918.        S_UNLOCK(&(slckP->locklock));
  919. #ifdef LOCKDEBUG
  920.        printf("OUT: ");
  921.        PRINT_LOCK(slckP);
  922. #endif
  923. #ifdef PARALLELDEBUG
  924.        EndParallelDebugInfo(PDI_SHAREDLOCK);
  925. #endif
  926.        return;
  927.     case SHAREDLOCK:
  928.        (slckP->nshlocks)++;
  929.        S_UNLOCK(&(slckP->locklock));
  930. #ifdef LOCKDEBUG
  931.        printf("OUT: ");
  932.        PRINT_LOCK(slckP);
  933. #endif
  934. #ifdef PARALLELDEBUG
  935.        EndParallelDebugInfo(PDI_SHAREDLOCK);
  936. #endif
  937.        return;
  938.     case EXCLUSIVELOCK:
  939.        (slckP->nshlocks)++;
  940.        S_UNLOCK(&(slckP->locklock));
  941.        S_LOCK(&(slckP->shlock));
  942.        (slckP->nshlocks)--;
  943.        S_UNLOCK(&(slckP->comlock));
  944.        goto sh_try_again;
  945.      }
  946. }
  947.  
  948. void
  949. SharedUnlock(lockid)
  950. int lockid;
  951. {
  952.     SLock *slckP;
  953.     slckP = &(SLockArray[lockid]);
  954. #ifdef LOCKDEBUG
  955.     printf("Proc %d SharedUnlock(%d)\n", MyPid, lockid);
  956.     printf("IN: ");
  957.     PRINT_LOCK(slckP);
  958. #endif
  959.     S_LOCK(&(slckP->locklock));
  960.     (slckP->nshlocks)--;
  961.     if (slckP->nshlocks == 0) {
  962.        slckP->flag = NOLOCK;
  963.        S_UNLOCK(&(slckP->exlock));
  964.      }
  965.     S_UNLOCK(&(slckP->locklock));
  966. #ifdef LOCKDEBUG
  967.        printf("OUT: ");
  968.        PRINT_LOCK(slckP);
  969. #endif
  970.     return;
  971. }
  972.  
  973. void
  974. ExclusiveLock(lockid)
  975. int lockid;
  976. {
  977.     SLock *slckP;
  978. #ifdef PARALLELDEBUG
  979.     BeginParallelDebugInfo(PDI_EXCLUSIVELOCK);
  980. #endif
  981.     slckP = &(SLockArray[lockid]);
  982. #ifdef LOCKDEBUG
  983.     printf("Proc %d ExclusiveLock(%d)\n", MyPid, lockid);
  984.     printf("IN: ");
  985.     PRINT_LOCK(slckP);
  986. #endif
  987. ex_try_again:
  988.     S_LOCK(&(slckP->locklock));
  989.     switch (slckP->flag) {
  990.     case NOLOCK:
  991.     slckP->flag = EXCLUSIVELOCK;
  992.     S_LOCK(&(slckP->exlock));
  993.     S_LOCK(&(slckP->shlock));
  994.     S_UNLOCK(&(slckP->locklock));
  995. #ifdef LOCKDEBUG
  996.        printf("OUT: ");
  997.        PRINT_LOCK(slckP);
  998. #endif
  999. #ifdef PARALLELDEBUG
  1000.     EndParallelDebugInfo(PDI_EXCLUSIVELOCK);
  1001. #endif
  1002.     return;
  1003.     case SHAREDLOCK:
  1004.     case EXCLUSIVELOCK:
  1005.     S_UNLOCK(&(slckP->locklock));
  1006.     S_LOCK(&(slckP->exlock));
  1007.     S_UNLOCK(&(slckP->exlock));
  1008.     goto ex_try_again;
  1009.       }
  1010. }
  1011.  
  1012. void
  1013. ExclusiveUnlock(lockid)
  1014. int lockid;
  1015. {
  1016.     SLock *slckP;
  1017.     int i;
  1018.  
  1019.     slckP = &(SLockArray[lockid]);
  1020. #ifdef LOCKDEBUG
  1021.     printf("Proc %d ExclusiveUnlock(%d)\n", MyPid, lockid);
  1022.     printf("IN: ");
  1023.     PRINT_LOCK(slckP);
  1024. #endif
  1025.     S_LOCK(&(slckP->locklock));
  1026.     /* -------------
  1027.      *  give favor to read processes
  1028.      * -------------
  1029.      */
  1030.     slckP->flag = NOLOCK;
  1031.     if (slckP->nshlocks > 0) {
  1032.     while (slckP->nshlocks > 0) {
  1033.        S_UNLOCK(&(slckP->shlock));
  1034.        S_LOCK(&(slckP->comlock));
  1035.      }
  1036.     S_UNLOCK(&(slckP->shlock));
  1037.       }
  1038.     else {
  1039.       S_UNLOCK(&(slckP->shlock));
  1040.      }
  1041.     S_UNLOCK(&(slckP->exlock));
  1042.     S_UNLOCK(&(slckP->locklock));
  1043. #ifdef LOCKDEBUG
  1044.        printf("OUT: ");
  1045.        PRINT_LOCK(slckP);
  1046. #endif
  1047.     return;
  1048. }
  1049.  
  1050. bool
  1051. LockIsFree(lockid)
  1052. int lockid;
  1053. {
  1054.     return(SLockArray[lockid].flag == NOLOCK);
  1055. }
  1056.  
  1057. #endif /* HAS_TEST_AND_SET */
  1058.